package com.alibaba.citrus.cr.mn.order.center.facade.service.impl;

import com.alibaba.citrus.cr.common.annotation.FacadeInvoker;
import com.alibaba.citrus.cr.common.enums.ordercenter.DictionaryTypeEnum;
import com.alibaba.citrus.cr.common.exception.FunctionException;
import com.alibaba.citrus.cr.common.lock.SaleRedisLock;
import com.alibaba.citrus.cr.mn.order.center.common.util.TrimUtils;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.BusinessChannelAbilityAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.DictionaryVerifyAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.SalesOrgAbilityAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.response.BusinessChannelDTO;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.response.SalesBizOrgQueryDTO;
import com.alibaba.cz.base.tool.Nullable;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.crforecastsales.activityuserecordrelation.dto.CreateActivityUseRecordRelationResponse;
import com.epoch.app.crforecastsales.activityuserecordrelation.dto.DeleteActivityUseRecordRelationRequest;
import com.epoch.app.crforecastsales.activityuserecordrelation.dto.QueryActivityUseRecordListByConditionRequest;
import com.epoch.app.crforecastsales.activityuserecordrelation.dto.QueryActivityUseRecordListByConditionResponse;
import com.epoch.app.crforecastsales.activityuserecordrelation.model.ActivityUseRecordRelation;
import com.epoch.app.crforecastsales.activityuserecordrelation.service.ActivityUseRecordRelationService;
import com.epoch.app.crforecastsales.domian.activityterm.dto.QueryTermSDOListByTermIdRequest;
import com.epoch.app.crforecastsales.domian.activityterm.service.ActivityTermService;
import com.epoch.app.crforecastsales.domian.activitytitle.dto.QueryActivityTitleByActivityIdRequest;
import com.epoch.app.crforecastsales.domian.activitytitle.service.ActivityTitleService;
import com.epoch.app.crforecastsales.domian.activitytitleext.model.ActivityTitleExt;
import com.epoch.app.crforecastsales.domian.activitytitleext.service.ActivityTitleExtService;
import com.epoch.app.crforecastsales.model.dto.*;
import com.epoch.app.crforecastsales.ofsactivitytermindex.dto.QueryActivityTermIndexByActivityIdRequest;
import com.epoch.app.crforecastsales.ofsactivitytermindex.dto.QueryActivityTermIndexByActivityIdResponse;
import com.epoch.app.crforecastsales.ofsactivitytermindex.model.OfsActivityTermIndex;
import com.epoch.app.crforecastsales.ofsactivitytermindex.service.OfsActivityTermIndexService;
import com.epoch.app.crpricecenter.model.enums.ActivityTypeEnum;
import com.epoch.app.mnordercenter.activitybiz.dto.BatchCoverActivityRequest;
import com.epoch.app.mnordercenter.activitybiz.dto.BatchDeductActivityRequest;
import com.epoch.app.mnordercenter.activitybiz.service.ActivityBizService;
import com.epoch.app.mnordercenter.model.dto.*;
import com.google.common.collect.Lists;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.alibaba.citrus.cr.mn.order.center.common.constants.RedisLockConstants.*;


/**
 * @author juxuan
 * @create 2023-08-17 11:55 AM
 */
@Service
@Primary
public class ActivityBizServiceImpl implements ActivityBizService {

    private static final Log log = Log.getLogger(ActivityBizServiceImpl.class);

    @Autowired
    private OfsActivityTermIndexService ofsActivityTermIndexService;

    @Autowired
    private ActivityTermService activityTermService;

    @Autowired
    private ActivityUseRecordRelationService activityUseRecordRelationService;

    @Autowired
    private ActivityTitleService activityTitleService;

    @Autowired
    private ActivityTitleExtService activityTitleExtService;

    @Resource
    private SalesOrgAbilityAdapter salesOrgAbilityAdapter;

    @Resource
    private BusinessChannelAbilityAdapter businessChannelAbilityAdapter;

    @Resource
    private DictionaryVerifyAdapter dictionaryVerifyAdapter;

    private final List<String> NORMAL_ACTIVITY_TYPE = Lists.newArrayList("ZS01", "ZS02", "ZS03");

    @Resource(name = "activityTaskExecutor")
    private ThreadPoolTaskExecutor activityTaskExecutor;

    /**
     * 批量活动扣减
     */
    @Override
    @FacadeInvoker(value = "促销活动批量扣减", errorCode = "OC-05-001-01-16-003")
    public Result<List<DeductActivityDocResp>> batchDeductActivity(BatchDeductActivityRequest request) {
        log.info("ActivityBizServiceImpl#batchDeductActivity request={}", JSONObject.toJSONString(request));
        long startTime = System.currentTimeMillis();
        String lockKey = ACTIVITY_BIZ_PREFIX + DigestUtils.md5Hex(JSON.toJSONString(request));
        try (SaleRedisLock lock = new SaleRedisLock(CACHE_CODE, lockKey, TIMEOUT_MSECS, EXPIRE_MSECS, SLEEP_MILLIS)) {
            if (!lock.lock()) {
                log.error("ActivityBizServiceImpl#batchDeductActivity 分布式锁获取失败 lockKey={}", lockKey);
                return Result.fail("OC-00-000-01-99-002", "分布式锁获取失败");
            }
            checkParams(request);
            List<DeductActivityDocResp> response = new ArrayList<>();
            List<DeductActivityDoc> deductActivityDocs = request.getDeductActivityDocs();

            //异步调用扣减
            List<Future<DeductActivityDocResp>> respList = new ArrayList<>();
            deductActivityDocs.forEach(x -> {
                CompletableFuture<DeductActivityDocResp> future = CompletableFuture.supplyAsync(() ->
                        deductActivity(x, lockKey, request.getOperator()), activityTaskExecutor);
                respList.add(future);
            });

            respList.forEach(x -> {
                DeductActivityDocResp deductActivityDocResp = null;
                try {
                    deductActivityDocResp = x.get();
                } catch (InterruptedException | ExecutionException e) {
                    log.error("多线程扣减活动异常", e);
                }
                response.add(deductActivityDocResp);
            });
            long endTime = System.currentTimeMillis();
            log.info("ActivityBizServiceImpl#batchDeductActivity startTime={}, endTime={}, executionTime={}",
                    startTime, endTime, endTime - startTime);
            return Result.listSuccess(response, response.size());
        } catch (Exception e) {
            log.info("ActivityBizServiceImpl#batchDeductActivity error={}", e);
            throw e;
        }
    }

    /**
     * 活动扣减
     */
    public DeductActivityDocResp deductActivity(DeductActivityDoc deductActivityDoc, String sequenceNo, String operator) {
        log.info("ActivityBizServiceImpl#deductActivity request={}", JSONObject.toJSONString(deductActivityDoc));
        long startTime = System.currentTimeMillis();
        long queryTermStart = 0;
        long queryTermEnd = 0;
        long queryTitleStart = 0;
        long queryTitleEnd = 0;
        long queryUseStart = 0;
        long queryUseEnd = 0;
        long queryExtStart = 0;
        long queryExtEnd = 0;
        long updateExtStart = 0;
        long updateExtEnd = 0;
        long checkExtStart = 0;
        long checkExtEnd = 0;
        long updateTermStart = 0;
        long updateTermEnd = 0;
        long checkTermStart = 0;
        long checkTermEnd = 0;
        long createUseStart = 0;
        long createUseEnd = 0;

        DeductActivityDocResp resp = new DeductActivityDocResp();
        try {
            //校验term表是否存在该活动
            QueryTermSDOListByTermIdRequest activityTermReq = new QueryTermSDOListByTermIdRequest();
            activityTermReq.setActivityId(deductActivityDoc.getActivityId());
            activityTermReq.setTermId(deductActivityDoc.getActivityTermId());
            queryTermStart = System.currentTimeMillis();
            ActivityTermLoadListVO activityTerm = activityTermService.queryTermSDOListByTermId(activityTermReq);
            queryTermEnd = System.currentTimeMillis();

            //校验title表是否存在该活动
            QueryActivityTitleByActivityIdRequest activityTitledReq = new QueryActivityTitleByActivityIdRequest();
            activityTitledReq.setActivityId(deductActivityDoc.getActivityId());
            queryTitleStart = System.currentTimeMillis();
            ActivityTitleLoadListVO activityTitle = activityTitleService.queryActivityTitleByActivityId(activityTitledReq);
            queryTitleEnd = System.currentTimeMillis();

            if (StringUtils.isEmpty(activityTerm.getActivityId()) || StringUtils.isEmpty(activityTitle.getActivityId())) {
                resp.setSuccess(false);
                resp.setErrorCode("OC-05-001-01-16-006");
                resp.setMessage("系统中不存在相关活动主数据，不允许进行活动扣减");
                log.info("系统中不存在相关活动主数据，不允许进行活动扣减");
                return resp;
            }

            //判断是否已使用过活动优惠
            QueryActivityUseRecordListByConditionRequest activityUseRecordReq = new QueryActivityUseRecordListByConditionRequest();
            activityUseRecordReq.setActivityId(deductActivityDoc.getActivityId());
            activityUseRecordReq.setActivityTermId(deductActivityDoc.getActivityTermId());
            activityUseRecordReq.setSubOrderId(deductActivityDoc.getActivityDocLineId());
            activityUseRecordReq.setMainOrderId(deductActivityDoc.getActivityDocId());
            queryUseStart = System.currentTimeMillis();
            QueryActivityUseRecordListByConditionResponse activityUseRecordResp = activityUseRecordRelationService.queryActivityUseRecordListByCondition(activityUseRecordReq);
            queryUseEnd = System.currentTimeMillis();

            if (!CollectionUtils.isEmpty(activityUseRecordResp.getResult())) {
                resp.setSuccess(false);
                resp.setErrorCode("OC-05-001-01-16-007");
                resp.setMessage("该单据已经进行活动占用，不允许重复传输");
                return resp;
            }

            //扣减金额转换
            Long amount = transferAmount(deductActivityDoc.getAmount());
            //判断活动类型，不在普通活动列表内的活动仅扣减金额
            boolean deductionQuantity = NORMAL_ACTIVITY_TYPE.contains(activityTitle.getActivityFacadeCode());

            //判断是否为共享活动，扣减ext表
            if (Objects.equals(activityTitle.getControlByGroupFlag(), "X")) {
                ActivityTitleExtCreateRequest activityTitleExtReq = new ActivityTitleExtCreateRequest();
                activityTitleExtReq.setActivityNoteId(activityTitle.getActivityNoteId());
                queryExtStart = System.currentTimeMillis();
                ActivityTitleExt activityTitleExt = activityTitleExtService.queryActivityTitleExt(activityTitleExtReq);
                queryExtEnd = System.currentTimeMillis();

                if (StringUtils.isNotEmpty(activityTitleExt.getActivityNoteId())) {
                    //扣减拓展表
                    ActivityTitleExtUpdateRequest updateExtRequest = ActivityTitleExtUpdateRequest.builder()
                            .id(activityTitleExt.getId())
                            .activityOccupyFee(amount)
                            .activityOccupyQuantity(deductionQuantity ? Long.parseLong(deductActivityDoc.getQuantity()) : 0)
                            .createId(activityTitleExt.getCreator())
                            .updateId(operator)
                            .version(activityTitleExt.getVersion())
                            .build();
                    updateExtStart = System.currentTimeMillis();
                    Integer count = activityTitleExtService.updateOccupyDataForDifference(updateExtRequest).getCount();
                    updateExtEnd = System.currentTimeMillis();

                    if (count == 0) {
                        //更新行为0，进行原因判断
                        checkExtStart = System.currentTimeMillis();
                        ActivityTitleExt checkExt = activityTitleExtService.queryActivityTitleExt(activityTitleExtReq);
                        checkExtEnd = System.currentTimeMillis();
                        if (checkExt.getApplyFee() - checkExt.getActivityOccupyFee() < amount) {
                            //金额不足
                            log.info("ext表活动金额不足, 活动扣减失败！活动便签ID:{}, 扣减金额:{}, 便签剩余金额:{}",
                                    checkExt.getActivityNoteId(), amount, checkExt.getApplyFee() - checkExt.getActivityOccupyFee());
                            resp.setSuccess(false);
                            resp.setErrorCode("OC-05-001-01-16-010");
                            resp.setMessage("扣减失败,金额不足");
                            return resp;
                        }
                        if (deductionQuantity) {
                            if (checkExt.getApplyItemQuantity() - checkExt.getActivityOccupyQuantity() < Long.parseLong(deductActivityDoc.getQuantity())) {
                                //活动量不足
                                log.info("ext表活动量不足, 活动扣减失败！活动便签ID:{}, 扣减量:{}, 便签剩余量:{}",
                                        checkExt.getActivityNoteId(), deductActivityDoc.getQuantity(), checkExt.getApplyItemQuantity() - checkExt.getActivityOccupyQuantity());
                                resp.setSuccess(false);
                                resp.setErrorCode("OC-05-001-01-16-009");
                                resp.setMessage("扣减失败,活动量不足");
                                return resp;
                            }
                        }
                    }
                }
            }
            //扣减term表
            ActivityTermUpdateRequest updateTermRequest = ActivityTermUpdateRequest.builder()
                    .id(activityTerm.getId())
                    .activityOccupyFee(amount)
                    .activityOccupyQuantity(deductionQuantity ? Integer.parseInt(deductActivityDoc.getQuantity()) : 0)
                    .createId(activityTerm.getCreator())
                    .updateId(operator)
                    .version(activityTerm.getVersion())
                    .build();
            updateTermStart = System.currentTimeMillis();
            Integer count = activityTermService.updateOccupyDataForDifference(updateTermRequest).getCount();
            updateTermEnd = System.currentTimeMillis();

            if (count == 0) {
                //更新行为0，进行原因判断
                checkTermStart = System.currentTimeMillis();
                ActivityTermLoadListVO checkTerm = activityTermService.queryTermSDOListByTermId(activityTermReq);
                checkTermEnd = System.currentTimeMillis();
                if (checkTerm.getApplyFee() - checkTerm.getActivityOccupyFee() < amount) {
                    log.info("term表活动金额不足, 活动扣减失败！活动ID:{}, 扣减金额:{}, 活动剩余金额:{}", checkTerm.getActivityId(), amount, checkTerm.getApplyFee() - checkTerm.getActivityOccupyFee());
                    resp.setSuccess(false);
                    resp.setErrorCode("OC-05-001-01-16-010");
                    resp.setMessage("扣减失败,金额不足");
                    return resp;
                }
                if (deductionQuantity) {
                    if (checkTerm.getApplyItemQuantity() - checkTerm.getActivityOccupyQuantity() < Long.parseLong(deductActivityDoc.getQuantity())) {
                        log.info("term表活动量不足, 活动扣减失败！活动ID:{}, 扣减量:{}, 活动剩余量:{}", checkTerm.getActivityId(), deductActivityDoc.getQuantity(), checkTerm.getApplyItemQuantity() - checkTerm.getActivityOccupyQuantity());
                        resp.setSuccess(false);
                        resp.setErrorCode("OC-05-001-01-16-009");
                        resp.setMessage("扣减失败,活动量不足");
                        return resp;
                    }
                }
            }

            Map<String, String> map = new HashMap<>();
            map.put("forecastOrderBizId", deductActivityDoc.getActivityDocId());
            //新增活动使用记录
            ActivityUseRecordRelationCreateRequest createUseRequest = ActivityUseRecordRelationCreateRequest.builder()
                    //活动 id
                    .activityId(deductActivityDoc.getActivityId())
                    //活动项目 id
                    .activityTermId(deductActivityDoc.getActivityTermId())
                    //主单号
                    .mainOrderId(deductActivityDoc.getActivityDocId())
                    //子单号
                    .subOrderId(deductActivityDoc.getActivityDocLineId())
                    //货品数量
                    .itemQuantity(Long.valueOf(deductActivityDoc.getQuantity()))
                    //活动占用费用
                    .activityOccupyFee(amount)
                    //资源占用序列号
                    .sequenceNo(sequenceNo)
                    .createId(operator)
                    .updateId(operator)
                    .features(JSON.toJSONString(map))
                    .build();
            createUseStart = System.currentTimeMillis();
            CreateActivityUseRecordRelationResponse activityUseRecordRelation = activityUseRecordRelationService.createActivityUseRecordRelation(createUseRequest);
            createUseEnd = System.currentTimeMillis();
            resp.setSuccess(true);
            resp.setMessage("活动扣减成功");
            resp.setDeductActivityId(activityUseRecordRelation.getLastInsertId());

            log.info("ActivityBizServiceImpl#deductActivity queryActivityTermTime={}, queryActivityTitleTime={}, queryUseTime={}, queryExtTime={}, updateExtTime={}, checkExtTime={}, updateTermTime={}, checkTermTime={}, createUseTime={}, executionTime={}",
                    queryTermEnd - queryTermStart,
                    queryTitleEnd - queryTitleStart,
                    queryUseEnd - queryUseStart,
                    queryExtEnd - queryExtStart,
                    updateExtEnd - updateExtStart,
                    checkExtEnd - checkExtStart,
                    updateTermEnd - updateTermStart,
                    checkTermEnd - checkTermStart,
                    createUseEnd - createUseStart,
                    System.currentTimeMillis() - startTime);
        } catch (RuntimeException e) {
            log.info("ActivityBizServiceImpl#deductActivity error={}", e);
            resp.setSuccess(false);
            resp.setErrorCode("OC-05-001-01-16-005");
            resp.setMessage("促销活动扣减失败");
        }
        return resp;
    }

    /**
     * 批量活动释放
     */
    @Override
    @FacadeInvoker(value = "促销活动批量释放", errorCode = "OC-05-001-01-16-002")
    public Result<List<CoverActivityResp>> batchCoverActivity(BatchCoverActivityRequest request) {
        long startTime = System.currentTimeMillis();
        log.info("ActivityBizServiceImpl#batchCoverActivity request={}", JSONObject.toJSONString(request));
        String lockKey = ACTIVITY_BIZ_PREFIX + DigestUtils.md5Hex(JSON.toJSONString(request));
        log.info("ActivityBizServiceImpl#batchCoverActivity lockKey={}", lockKey);
        try (SaleRedisLock lock = new SaleRedisLock(CACHE_CODE, lockKey, TIMEOUT_MSECS, EXPIRE_MSECS, SLEEP_MILLIS)) {
            if (!lock.lock()) {
                log.error("SalesOrderAtomServiceImpl#batchCreate 分布式锁获取失败 lockKey={}", lockKey);
                return Result.fail("OC-00-000-01-99-002", "分布式锁获取失败");
            }
            checkParams(request);
            List<CoverActivityResp> response = new ArrayList<>();
            List<CoverActivityDocs> coverActivityDocs = request.getCoverActivityDocs();

            //异步调用回补
            Map<String, Future<CoverActivityResp>> map = new HashMap<>();
            List<Future<CoverActivityResp>> respList = new ArrayList<>();
            coverActivityDocs.forEach(x -> {
                CompletableFuture<CoverActivityResp> future = CompletableFuture.supplyAsync(() ->
                        coverActivity(x, request.getOperator()), activityTaskExecutor);
                respList.add(future);
            });

            respList.forEach(x -> {
                CoverActivityResp coverActivityResp = null;
                try {
                    coverActivityResp = x.get();
                } catch (InterruptedException | ExecutionException e) {
                    log.error("多线程扣减活动异常", e);
                }
                response.add(coverActivityResp);
            });
            long endTime = System.currentTimeMillis();
            log.info("ActivityBizServiceImpl#batchCoverActivity startTime={}, endTime={}, executionTime={}",
                    startTime, endTime, endTime - startTime);
            return Result.listSuccess(response, response.size());
        } catch (Exception e) {
            log.info("ActivityBizServiceImpl#batchCoverActivity error={}", e);
            throw e;
        }
    }

    public CoverActivityResp coverActivity(CoverActivityDocs coverActivityDocs, String operator) {
        log.info("ActivityBizServiceImpl#coverActivity request={}", JSONObject.toJSONString(coverActivityDocs));
        long startTime = System.currentTimeMillis();
        long queryUseStart = 0;
        long queryUseEnd = 0;
        long circulateStart = 0;
        long circulateEnd = 0;
        long queryTermStart = 0;
        long queryTermEnd = 0;
        long queryTitleStart = 0;
        long queryTitleEnd = 0;
        long queryExtStart = 0;
        long queryExtEnd = 0;
        long updateExtStart = 0;
        long updateExtEnd = 0;
        long checkExtStart = 0;
        long checkExtEnd = 0;
        long updateTermStart = 0;
        long updateTermEnd = 0;
        long checkTermStart = 0;
        long checkTermEnd = 0;
        long createUseStart = 0;
        long createUseEnd = 0;
        CoverActivityResp resp = new CoverActivityResp();
        try {
            //确认是否存在有效活动扣减记录
            QueryActivityUseRecordListByConditionRequest activityUseRecordReq = new QueryActivityUseRecordListByConditionRequest();
            activityUseRecordReq.setSubOrderId(coverActivityDocs.getActivityDocLineId());
            activityUseRecordReq.setMainOrderId(coverActivityDocs.getActivityDocId());
            queryUseStart = System.currentTimeMillis();
            QueryActivityUseRecordListByConditionResponse activityUseRecordList =
                    activityUseRecordRelationService.queryActivityUseRecordListByCondition(activityUseRecordReq);
            queryUseEnd = System.currentTimeMillis();
            if (CollectionUtils.isEmpty(activityUseRecordList.getResult())) {
                resp.setSuccess(false);
                resp.setErrorCode("OC-05-001-01-16-008");
                resp.setMessage("系统中不存在相关活动扣减记录，不允许进行活动释放");
                return resp;
            }
            //获取该订单所有活动使用记录进行回补
            List<ActivityUseRecordRelation> useRecordList = activityUseRecordList.getResult();
            int i = 1;
            circulateStart = System.currentTimeMillis();
            for (ActivityUseRecordRelation activityUseRecord : useRecordList) {
                QueryTermSDOListByTermIdRequest activityTermReq = new QueryTermSDOListByTermIdRequest();
                activityTermReq.setActivityId(activityUseRecord.getActivityId());
                activityTermReq.setTermId(activityUseRecord.getActivityTermId());
                queryTermStart = System.currentTimeMillis();
                ActivityTermLoadListVO activityTerm = activityTermService.queryTermSDOListByTermId(activityTermReq);
                queryTermEnd = System.currentTimeMillis();

                QueryActivityTitleByActivityIdRequest activityTitledReq = new QueryActivityTitleByActivityIdRequest();
                activityTitledReq.setActivityId(activityUseRecord.getActivityId());
                queryTitleStart = System.currentTimeMillis();
                ActivityTitleLoadListVO activityTitle = activityTitleService.queryActivityTitleByActivityId(activityTitledReq);
                queryTitleEnd = System.currentTimeMillis();

                if (StringUtils.isEmpty(activityTerm.getActivityId()) || StringUtils.isEmpty(activityTitle.getActivityId())) {
                    resp.setSuccess(false);
                    resp.setErrorCode("OC-05-001-01-16-006");
                    resp.setMessage("系统中不存在相关活动主数据,不可进行回补");
                    log.info("系统中不存在相关活动主数据,不可进行回补");
                    return resp;
                }
                //判断活动类型，不在普通活动列表内的活动仅回补金额
                boolean deductionQuantity = NORMAL_ACTIVITY_TYPE.contains(activityTitle.getActivityFacadeCode());

                //校验是否为共享活动，回补Ext表
                if (Objects.equals(activityTitle.getControlByGroupFlag(), "X")) {
                    ActivityTitleExtCreateRequest activityTitleExtReq = new ActivityTitleExtCreateRequest();
                    activityTitleExtReq.setActivityNoteId(activityTitle.getActivityNoteId());
                    queryExtStart = System.currentTimeMillis();
                    ActivityTitleExt activityTitleExt = activityTitleExtService.queryActivityTitleExt(activityTitleExtReq);
                    queryExtEnd = System.currentTimeMillis();

                    if (StringUtils.isNotEmpty(activityTitleExt.getActivityNoteId())) {
                        //回补拓展表
                        ActivityTitleExtUpdateRequest updateExtRequest = ActivityTitleExtUpdateRequest.builder()
                                .id(activityTitleExt.getId())
                                .activityOccupyFee(activityUseRecord.getActivityOccupyFee())
                                .activityOccupyQuantity(deductionQuantity ? activityUseRecord.getItemQuantity() : 0)
                                .createId(activityTitleExt.getCreator())
                                .updateId(operator)
                                .version(activityTitleExt.getVersion())
                                .build();
                        updateExtStart = System.currentTimeMillis();
                        Integer count = activityTitleExtService.updateCoverDataForDifference(updateExtRequest).getCount();
                        updateExtEnd = System.currentTimeMillis();

                        if (count == 0) {
                            //更新行为0，进行原因判断
                            checkExtStart = System.currentTimeMillis();
                            ActivityTitleExt checkExt = activityTitleExtService.queryActivityTitleExt(activityTitleExtReq);
                            checkExtEnd = System.currentTimeMillis();
                            if (activityUseRecord.getActivityOccupyFee() - checkExt.getActivityOccupyFee() > 0) {
                                log.info("ext表活动占用金额不够回补，回补活动失败！活动使用id:{}, 活动回补金额:{}, 已经占用的金额:{}",
                                        activityUseRecord.getId(), activityUseRecord.getActivityOccupyFee(), checkExt.getActivityOccupyFee());
                                resp.setSuccess(false);
                                resp.setErrorCode("OC-05-001-01-16-011");
                                resp.setMessage("回补失败,占用金额不足");
                                return resp;
                            }
                            if (deductionQuantity) {
                                if (activityUseRecord.getItemQuantity() - checkExt.getActivityOccupyQuantity() > 0) {
                                    log.info("ext表活动占用量不够回补，回补活动失败！活动使用id:{}, 活动回补量:{}, 已经占用的量:{}",
                                            activityUseRecord.getId(), activityUseRecord.getItemQuantity(), checkExt.getActivityOccupyQuantity());
                                    resp.setSuccess(false);
                                    resp.setErrorCode("OC-05-001-01-16-012");
                                    resp.setMessage("回补失败,活动量不足");
                                    return resp;
                                }
                            }
                        }
                    }
                }
                //回补term表
                ActivityTermUpdateRequest updateTermRequest = ActivityTermUpdateRequest.builder()
                        .id(activityTerm.getId())
                        .activityOccupyFee(activityUseRecord.getActivityOccupyFee())
                        .activityOccupyQuantity(deductionQuantity ? activityUseRecord.getItemQuantity().intValue() : 0)
                        .createId(activityTerm.getCreator())
                        .updateId(operator)
                        .version(activityTerm.getVersion())
                        .build();
                updateTermStart = System.currentTimeMillis();
                Integer count = activityTermService.updateCoverDataForDifference(updateTermRequest).getCount();
                updateTermEnd = System.currentTimeMillis();
                if (count == 0) {
                    checkTermStart = System.currentTimeMillis();
                    ActivityTermLoadListVO checkTerm = activityTermService.queryTermSDOListByTermId(activityTermReq);
                    checkTermEnd = System.currentTimeMillis();
                    if (activityUseRecord.getActivityOccupyFee() - checkTerm.getActivityOccupyFee() > 0) {
                        log.info("term表活动占用金额不够回补, 回补活动失败！活动使用id:{}, 活动回补金额:{}, 已经占用的金额:{}",
                                activityUseRecord.getId(), activityUseRecord.getActivityOccupyFee(), checkTerm.getActivityOccupyFee());
                        resp.setSuccess(false);
                        resp.setErrorCode("OC-05-001-01-16-011");
                        resp.setMessage("回补失败,占用金额不足");
                        return resp;
                    }
                    if (deductionQuantity) {
                        if (activityUseRecord.getItemQuantity() - checkTerm.getActivityOccupyQuantity() > 0) {
                            log.info("term表活动占用量不够回补, 回补活动失败！活动使用id:{}, 活动回补量:{}, 已经占用的量:{}",
                                    activityUseRecord.getId(), activityUseRecord.getItemQuantity(), checkTerm.getActivityOccupyQuantity());
                            resp.setSuccess(false);
                            resp.setErrorCode("OC-05-001-01-16-012");
                            resp.setMessage("回补失败,活动量不足");
                            return resp;
                        }
                    }
                }
                //逻辑删除使用记录表
                DeleteActivityUseRecordRelationRequest updateUseRecordReq = DeleteActivityUseRecordRelationRequest.builder()
                        .id(activityUseRecord.getId())
                        .operator(operator)
                        .build();
                createUseStart = System.currentTimeMillis();
                activityUseRecordRelationService.deleteActivityUseRecordRelation(updateUseRecordReq);
                createUseEnd = System.currentTimeMillis();
                resp.setSuccess(true);
                resp.setMessage("活动释放成功");
                log.info("ActivityBizServiceImpl#coverActivity_circulateDetailTime_{} queryTermTime={},queryTitleTime={},queryExtTime={},updateExtTime={},checkExtTime={},updateTermTime={},checkTermTime={},createUseTime={}",
                        i++,
                        queryTermEnd-queryTermStart,
                        queryTitleEnd-queryTitleStart,
                        queryExtEnd-queryExtStart,
                        updateExtEnd-updateExtStart,
                        checkExtEnd-checkExtStart,
                        updateTermEnd-updateTermStart,
                        checkTermEnd-checkTermStart,
                        createUseEnd-createUseStart);
            }
            circulateEnd = System.currentTimeMillis();

            log.info("ActivityBizServiceImpl#coverActivity order_use_activity_total={},queryUseTime={},circulateTime={},executionTime={}",
                    useRecordList.size(),
                    queryUseEnd - queryUseStart,
                    circulateEnd - circulateStart,
                    System.currentTimeMillis() - startTime);
        } catch (RuntimeException e) {
            log.info("ActivityBizServiceImpl#coverActivity error={}", e);
            resp.setSuccess(false);
            resp.setErrorCode("OC-05-001-01-16-004");
            resp.setMessage("促销活动释放失败");
        }
        return resp;
    }


    /**
     * 活动查询
     */
    @Override
    @FacadeInvoker(value = "促销活动剩余量查询", errorCode = "OC-05-001-01-16-001")
    public Result<List<QueryActivityResp>> queryActivity(QueryActivityRequest request) {
        log.info("ActivityBizServiceImpl#queryActivity request={}", JSONObject.toJSONString(request));
        checkParams(request);
        QueryActivityTermIndexByActivityIdRequest query = new QueryActivityTermIndexByActivityIdRequest();
        query.setActivityIds(request.getActivityIds());
        QueryActivityTermIndexByActivityIdResponse queryResult = ofsActivityTermIndexService.queryActivityTermIndexByActivityId(query);
        if (CollectionUtils.isEmpty(queryResult.getResult())) {
            return Result.success(null);
        }
        return Result.listSuccess(queryResultRich(queryResult.getResult()), queryResult.getResult().size());
    }

    /**
     * 校验入参
     */
    private <T> void checkParams(T request) {
        if (Objects.isNull(request)) {
            throw new FunctionException("OC-05-001-01-15-001");
        }
        //去除空格
        TrimUtils.removeSpace(request);
        if (request instanceof BatchDeductActivityRequest) {
            // 参数检查逻辑针对 BatchDeductActivityRequest 类型的请求
            BatchDeductActivityRequest req = (BatchDeductActivityRequest) request;
            checkBaseParams(req.getBusinessType(), req.getFromSys());

            if (StringUtils.isBlank(req.getOperator())) {
                throw new FunctionException("OC-05-001-01-15-030");
            } else if (req.getOperator().length() > 50) {
                throw new FunctionException("OC-05-001-01-15-031");
            }

            if (CollectionUtils.isEmpty(req.getDeductActivityDocs())) {
                throw new FunctionException("OC-05-001-01-15-013");
            }
            if (req.getDeductActivityDocs().size() > 100) {
                throw new FunctionException("OC-05-001-01-15-014");
            }
            boolean hasDuplicates = req.getDeductActivityDocs().stream().collect(Collectors.groupingBy(x -> Arrays.asList(x.getActivityDocId(), x.getActivityDocLineId(), x.getActivityId()))).values().stream().anyMatch(list -> list.size() > 1);
            if (hasDuplicates) {
                throw new FunctionException("OC-05-001-01-15-025");
            }

            req.getDeductActivityDocs().forEach(x -> {
                if (StringUtils.isBlank(x.getActivityDocId())) {
                    throw new FunctionException("OC-05-001-01-15-015");
                } else if (x.getActivityDocId().length() > 50) {
                    throw new FunctionException("OC-05-001-01-15-016");
                }

                if (StringUtils.isBlank(x.getActivityDocLineId())) {
                    throw new FunctionException("OC-05-001-01-15-017");
                } else if (x.getActivityDocLineId().length() > 50) {
                    throw new FunctionException("OC-05-001-01-15-018");
                }

                if (StringUtils.isBlank(x.getActivityId())) {
                    throw new FunctionException("OC-05-001-01-15-019");
                } else if (x.getActivityId().length() > 50) {
                    throw new FunctionException("OC-05-001-01-15-020");
                }

                if (StringUtils.isBlank(x.getActivityTermId())) {
                    throw new FunctionException("OC-05-001-01-15-021");
                } else if (x.getActivityTermId().length() > 50) {
                    throw new FunctionException("OC-05-001-01-15-022");
                }

                if (StringUtils.isBlank(x.getQuantity())) {
                    throw new FunctionException("OC-05-001-01-15-026");
                }
                if (x.getQuantity().length() > 10) {
                    throw new FunctionException("OC-05-001-01-15-027");
                }
                if (!checkPositiveInteger(x.getQuantity())) {
                    throw new FunctionException("OC-05-001-01-15-023");
                }

                if (StringUtils.isBlank(x.getAmount())) {
                    throw new FunctionException("OC-05-001-01-15-028");
                }
                if (x.getAmount().length() > 10) {
                    throw new FunctionException("OC-05-001-01-15-029");
                }
                if (!checkPositiveNumber(x.getAmount())) {
                    throw new FunctionException("OC-05-001-01-15-024");
                }
            });

        } else if (request instanceof BatchCoverActivityRequest) {
            // 参数检查逻辑针对 BatchCoverActivityRequest 类型的请求
            BatchCoverActivityRequest req = (BatchCoverActivityRequest) request;
            checkBaseParams(req.getBusinessType(), req.getFromSys());

            if (StringUtils.isBlank(req.getOperator())) {
                throw new FunctionException("OC-05-001-01-15-030");
            } else if (req.getOperator().length() > 50) {
                throw new FunctionException("OC-05-001-01-15-031");
            }

            if (CollectionUtils.isEmpty(req.getCoverActivityDocs())) {
                throw new FunctionException("OC-05-001-01-15-007");
            }
            if (req.getCoverActivityDocs().size() > 100) {
                throw new FunctionException("OC-05-001-01-15-008");
            }

            boolean hasDuplicates = req.getCoverActivityDocs().stream().collect(Collectors.groupingBy(x -> Arrays.asList(x.getActivityDocId(), x.getActivityDocLineId()))).values().stream().anyMatch(list -> list.size() > 1);
            if (hasDuplicates) {
                throw new FunctionException("OC-05-001-01-15-025");
            }

            req.getCoverActivityDocs().forEach(x -> {
                if (StringUtils.isBlank(x.getActivityDocId())) {
                    throw new FunctionException("OC-05-001-01-15-009");
                }
                if (x.getActivityDocId().length() > 50) {
                    throw new FunctionException("OC-05-001-01-15-010");
                }

                if (StringUtils.isBlank(x.getActivityDocLineId())) {
                    throw new FunctionException("OC-05-001-01-15-011");
                }
                if (x.getActivityDocLineId().length() > 50) {
                    throw new FunctionException("OC-05-001-01-15-012");
                }
            });
        } else if (request instanceof QueryActivityRequest) {
            // 参数检查逻辑针对 QueryActivityRequest 类型的请求
            QueryActivityRequest req = (QueryActivityRequest) request;
            if (CollectionUtils.isEmpty(req.getActivityIds())) {
                throw new FunctionException("OC-05-001-01-15-001");
            }
            if (req.getActivityIds().size() > 10) {
                throw new FunctionException("OC-05-001-01-15-002");
            }
            req.getActivityIds().forEach(x -> {
                if (StringUtils.isBlank(x)) {
                    throw new FunctionException("OC-05-001-01-15-019");
                }
                if (x.length() > 50) {
                    throw new FunctionException("OC-05-001-01-15-020");
                }
            });
        }
    }

    /**
     * 校验正整数
     */
    public boolean checkPositiveInteger(String input) {
        // 定义正则表达式
        String regex = "^[1-9]\\d*$";
        // 编译正则表达式
        Pattern pattern = Pattern.compile(regex);
        // 匹配输入是否符合正则表达式
        Matcher matcher = pattern.matcher(input);
        // 返回匹配结果
        return matcher.matches() && new BigDecimal("2147483647").compareTo(new BigDecimal(input)) > 0;
    }

    /**
     * 校验大于0的数，且最多有2位小数
     */
    public boolean checkPositiveNumber(String input) {
        // 定义正则表达式
        String regex = "^[1-9]\\d*(\\.\\d{1,2})?$";
        // 编译正则表达式
        Pattern pattern = Pattern.compile(regex);
        // 匹配输入是否符合正则表达式
        Matcher matcher = pattern.matcher(input);
        // 返回匹配结果
        return matcher.matches() && new BigDecimal("2147483647").compareTo(new BigDecimal(input)) > 0;
    }

    /**
     * 校验基础数据，目前仅业态与来源系统
     */
    public void checkBaseParams(String businessType, String fromSys) {
        if (!StringUtils.isBlank(businessType)) {
            if (businessType.length() > 50) {
                throw new FunctionException("OC-05-001-01-15-003");
            }
            dictionaryVerifyAdapter.verifyDictionary(DictionaryTypeEnum.BUSINESS_TYPE.getCode(), businessType, new FunctionException("OC-05-001-01-15-004"));
        }
        if (!StringUtils.isBlank(fromSys)) {
            if (fromSys.length() > 50) {
                throw new FunctionException("OC-05-001-01-15-005");
            }
            dictionaryVerifyAdapter.verifyDictionary(DictionaryTypeEnum.FROM_SYS.getCode(), fromSys, new FunctionException("OC-05-001-01-15-006"));
        }
    }

    /**
     * 时间戳转Date
     */
    public Date timestampToDate(Long timestamp) {
        return Objects.isNull(timestamp) ? null : new Date(timestamp);

    }

    /**
     * 活动查询结果丰富
     */
    public List<QueryActivityResp> queryResultRich(List<OfsActivityTermIndex> list) {
        List<QueryActivityResp> resultRich = list.stream().map(item -> {
            QueryActivityResp entity = new QueryActivityResp();
            entity.setActivityId(item.getSubActivityId());
            entity.setActivityTermId(item.getSubActivityTermId());
            // 1启用 2禁用
            entity.setActivityStatus(item.getSubStatus() == null ? null : item.getSubStatus().toString());
            entity.setSaleOrganizationCode(item.getMainSalesOrganization());
            entity.setSaleOrganizationName("");
            entity.setBusinessChannelCode(item.getMainSalesChannel());
            entity.setBusinessChannelName("");
            entity.setActivityNoteId(item.getMainActivityNoteId());
            entity.setActivityNoteName(item.getMainActivityNoteName());

            if (StringUtils.isNotEmpty(item.getMainActivityFacadeCode())) {
                entity.setActivityTypeCode(item.getMainActivityFacadeCode());
                Optional<ActivityTypeEnum> of = Optional.ofNullable(ActivityTypeEnum.of(item.getMainActivityFacadeCode()));
                if (of.isPresent()) {
                    of.ifPresent(o -> entity.setActivityTypeName(o.getLabel()));
                }
            }
            entity.setActivityStartDate(timestampToDate(item.getMainActivityStartDate()));
            entity.setActivityEndDate(timestampToDate(item.getMainActivityEndDate()));
            Long activityApplyItemQuantity = item.getSubApplyItemQuantity();
            entity.setApplyItemQuantity(String.valueOf(activityApplyItemQuantity));
            Long applyFee = item.getSubApplyFee();
            if (Objects.nonNull(applyFee)) {
                entity.setApplyFee(new BigDecimal(applyFee).divide(new BigDecimal(100)).toString());
            }
            Long activityOccupyQuantity = item.getSubActivityOccupyQuantity();
            entity.setActivityOccurrence(String.valueOf(activityOccupyQuantity));
            Long activityOccupyFee = item.getSubActivityOccupyFee();
            if (Objects.nonNull(activityOccupyFee)) {
                entity.setActivityOccurrenceFee(new BigDecimal(activityOccupyFee).divide(new BigDecimal(100)).toString());
            }

            //设置活动剩余量
            entity.setActivityRemaining(null);
            if (Objects.nonNull(activityApplyItemQuantity) && Objects.nonNull(activityOccupyQuantity)) {
                long activityRemaining = activityApplyItemQuantity - activityOccupyQuantity;
                entity.setActivityRemaining(Long.toString(activityRemaining));
            }
            //设置活动剩余费用
            entity.setActivityRemainingFee(null);
            if (Objects.nonNull(applyFee) && Objects.nonNull(activityOccupyFee)) {
                BigDecimal activityRemainingFee = new BigDecimal(applyFee - activityOccupyFee);
                entity.setActivityRemainingFee(activityRemainingFee.divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP).toString());
            }
            entity.setControlByGroupFlag(item.getMainControlByGroupFlag());

            //如果是按组管控，填充ext表相关的便签活动数据
            if (StringUtils.isNotBlank(item.getMainControlByGroupFlag()) && "X".equals(item.getMainControlByGroupFlag())) {
                String activityNoteId = item.getMainActivityNoteId();
                ActivityTitleExtCreateRequest activityTitleExtCreateRequest = new ActivityTitleExtCreateRequest();
                activityTitleExtCreateRequest.setActivityNoteId(activityNoteId);
                ActivityTitleExt activityTitleExt = activityTitleExtService.queryActivityTitleExt(activityTitleExtCreateRequest);
                if (Objects.nonNull(activityTitleExt)) {
                    Long noteApplyQuantity = Nullable.of(activityTitleExt.getApplyItemQuantity()).orElse(0L);
                    Long noteOccupyQuantity = Nullable.of(activityTitleExt.getActivityOccupyQuantity()).orElse(0L);
                    Long noteApplyFee = Nullable.of(activityTitleExt.getApplyFee()).orElse(0L);
                    Long noteOccupyFee = Nullable.of(activityTitleExt.getActivityOccupyFee()).orElse(0L);
                    long activityRemainQuantity = noteApplyQuantity - noteOccupyQuantity;
                    long activityRemainFee = noteApplyFee - noteOccupyFee;
                    entity.setNoteApplyQuantity(String.valueOf(noteApplyQuantity));
                    entity.setNoteApplyFee(String.valueOf(new BigDecimal(noteApplyFee).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP)));
                    entity.setNoteOccupyQuantity(String.valueOf(noteOccupyQuantity));
                    entity.setNoteOccupyFee(String.valueOf(new BigDecimal(noteOccupyFee).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP)));
                    entity.setNoteRemainQuantity(String.valueOf(activityRemainQuantity));
                    entity.setNoteRemainFee(String.valueOf(new BigDecimal(activityRemainFee).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP)));
                }
            }
            return entity;
        }).collect(Collectors.toList());
        richOrg(resultRich);
        richChannel(resultRich);
        return resultRich;
    }

    /**
     * 丰富组织信息
     */
    public void richOrg(List<QueryActivityResp> req) {
        log.info("ActivityBizServiceImpl#richOrg req={}", JSONObject.toJSONString(req));
        List<String> orgCodeList = req.stream().map(QueryActivityResp::getSaleOrganizationCode).distinct().collect(Collectors.toList());
        Map<String, SalesBizOrgQueryDTO> orgMap = salesOrgAbilityAdapter.querySalesOrgByCode(orgCodeList).stream().collect(Collectors.toMap(SalesBizOrgQueryDTO::getOrgCode, x -> x, (x, y) -> x));

        req.forEach(x -> {
            SalesBizOrgQueryDTO orgDTO = orgMap.get(x.getSaleOrganizationCode());
            if (orgDTO != null) {
                x.setSaleOrganizationName(orgDTO.getOrgName());
            }
        });
    }

    /**
     * 丰富渠道信息
     */
    public void richChannel(List<QueryActivityResp> req) {
        log.info("ActivityBizServiceImpl#richChannel req={}", JSONObject.toJSONString(req));
        List<String> channelCodeList = req.stream().map(QueryActivityResp::getBusinessChannelCode).distinct().collect(Collectors.toList());
        Map<String, BusinessChannelDTO> channelMap = businessChannelAbilityAdapter.queryBusinessChannel(channelCodeList).stream().collect(Collectors.toMap(BusinessChannelDTO::getChannelCode, x -> x, (x, y) -> x));

        req.forEach(x -> {
            BusinessChannelDTO channelDTO = channelMap.get(x.getBusinessChannelCode());
            if (channelDTO != null) {
                x.setBusinessChannelName(channelDTO.getChannelName());
            }
        });
    }

    /**
     * 金额转化
     */
    public Long transferAmount(String amount) {
        BigDecimal bigDecimal = new BigDecimal(amount); // 创建一个BigDecimal对象
        bigDecimal = bigDecimal.multiply(new BigDecimal(100)); // 将BigDecimal数值乘以100
        bigDecimal = bigDecimal.setScale(0, RoundingMode.HALF_UP); // 设置小数位数为0并进行四舍五入
        return bigDecimal.longValue();
    }

}